#!/usr/bin/env python3
"""
app.py - Flask 后端（生成历史买入信号）
- 输入：股票代码列表、策略名称、日期范围
- 输出：历史买入信号列表（股票代码、日期、收盘价、指标、触发条件）
- 支持 breakout 和 combined 策略
- 基于 yfinance 下载数据，优先使用缓存
- Web 页面支持多股票输入和信号展示
- 优化数据下载：仅下载必要时间段，拼接连续数据
"""
import traceback
import numpy as np
from flask import Flask, render_template, request, redirect, url_for, flash
from datetime import datetime as dt, timedelta

from data_loader import download_data, flatten_columns, get_default_start_date
from strategy import STRATEGIES, STRATEGY_DESCRIPTIONS

# ========= 全局路径 ========= #
APP = Flask(__name__)
APP.secret_key = "REPLACE_ME_WITH_RANDOM"

# ========= 路由 ========= #

@APP.route("/", methods=["GET", "POST"])
def index():
    default_end = dt.now().date() - timedelta(days=1)
    default_start = get_default_start_date(default_end)
    if request.method == "POST":
        try:
            tickers = [t.strip().upper() for t in request.form["tickers"].split(",") if t.strip()]
            start = request.form["start"]
            end = request.form["end"]
            strategy = request.form.get("strategy", "breakout")
            signals = generate_signals(tickers, start, end, strategy)
            return render_template("result.html", signals=signals, strategy=strategy)
        except Exception as e:
            traceback.print_exc()
            flash(str(e))
            return redirect(url_for("index"))
    return render_template(
        "index.html",
        strategies=STRATEGIES.keys(),
        strategy_descriptions=STRATEGY_DESCRIPTIONS,
        default_start=default_start,
        default_end=default_end
    )

# ========= 信号生成 ========= #

def generate_signals(tickers: list, start: str, end: str, strategy_name: str) -> list:
    """生成历史买入信号"""
    if strategy_name not in STRATEGIES:
        raise ValueError(f"未知策略: {strategy_name}")

    signals = []
    end_date = pd.to_datetime(end)
    for ticker in tickers:
        try:
            df = download_data(ticker, start, end)
            df = flatten_columns(df, ticker)
            df = df.asfreq("B")
            df["Close"] = df["Close"].ffill()  # 与回测一致
            if len(df) < 60:
                raise ValueError(f"{ticker} 数据不足 60 天")

            # 应用策略
            df = STRATEGIES[strategy_name](df)
            # 调试：打印最近3个交易日
            recent_dates = df.index[df.index <= end_date][-100:]
            # 收集买入信号
            for date, row in df.iterrows():
                if row["Signal"] == 1 and date in recent_dates:
                    trigger_conditions = []
                    if strategy_name == "slow_breakout":
                        trigger_conditions = [
                            f"RSI ({row['RSI']:.2f}) < 70",
                            f"SMA10 ({row['SMA10']:.2f}) > SMA20 ({row['SMA20']:.2f})"
                        ]
                    elif strategy_name == "fast_breakout":
                        trigger_conditions = [
                            f"RSI ({row['RSI']:.2f}) < 70",
                            f"SMA5 ({row['SMA5']:.2f}) > SMA10 ({row['SMA10']:.2f})"
                        ]
                    signals.append({
                        "ticker": ticker,
                        "date": date.strftime("%Y-%m-%d"),
                        "SMA5": round(row["SMA5"], 2),
                        "SMA10": round(row["SMA10"], 2),
                        "SMA20": round(row["SMA20"], 2),
                        "High20": round(row["High20"], 2),
                        "RSI": round(row["RSI"], 2),
                        "ATR": round(row["ATR"], 2),
                        "trigger_conditions": trigger_conditions
                    })
                    print(f"[INF] {ticker} {date.strftime('%Y-%m-%d')} 触发信号：{trigger_conditions}")

        except Exception as e:
            traceback.print_exc()
            print(f"[ERR] {ticker} 处理失败: {e}")
            continue

    return signals

# ========= 入口 ========= #

if __name__ == "__main__":
    import pandas as pd  # 确保在模块中使用时可用
    APP.run(host="0.0.0.0", port=9000, debug=True)
